
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="zh_Hans">
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>如何使用会话 &#8212; Django 3.2.11.dev 文档</title>
    <link rel="stylesheet" href="../../_static/default.css" type="text/css" />
    <link rel="stylesheet" href="../../_static/pygments.css" type="text/css" />
    <script type="text/javascript" id="documentation_options" data-url_root="../../" src="../../_static/documentation_options.js"></script>
    <script type="text/javascript" src="../../_static/jquery.js"></script>
    <script type="text/javascript" src="../../_static/underscore.js"></script>
    <script type="text/javascript" src="../../_static/doctools.js"></script>
    <script type="text/javascript" src="../../_static/language_data.js"></script>
    <link rel="index" title="索引" href="../../genindex.html" />
    <link rel="search" title="搜索" href="../../search.html" />
    <link rel="next" title="使用表单" href="../forms/index.html" />
    <link rel="prev" title="中间件" href="middleware.html" />



 
<script src="../../templatebuiltins.js"></script>
<script>
(function($) {
    if (!django_template_builtins) {
       // templatebuiltins.js missing, do nothing.
       return;
    }
    $(document).ready(function() {
        // Hyperlink Django template tags and filters
        var base = "../../ref/templates/builtins.html";
        if (base == "#") {
            // Special case for builtins.html itself
            base = "";
        }
        // Tags are keywords, class '.k'
        $("div.highlight\\-html\\+django span.k").each(function(i, elem) {
             var tagname = $(elem).text();
             if ($.inArray(tagname, django_template_builtins.ttags) != -1) {
                 var fragment = tagname.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + tagname + "</a>");
             }
        });
        // Filters are functions, class '.nf'
        $("div.highlight\\-html\\+django span.nf").each(function(i, elem) {
             var filtername = $(elem).text();
             if ($.inArray(filtername, django_template_builtins.tfilters) != -1) {
                 var fragment = filtername.replace(/_/, '-');
                 $(elem).html("<a href='" + base + "#" + fragment + "'>" + filtername + "</a>");
             }
        });
    });
})(jQuery);</script>

  </head><body>

    <div class="document">
  <div id="custom-doc" class="yui-t6">
    <div id="hd">
      <h1><a href="../../index.html">Django 3.2.11.dev 文档</a></h1>
      <div id="global-nav">
        <a title="Home page" href="../../index.html">Home</a>  |
        <a title="Table of contents" href="../../contents.html">Table of contents</a>  |
        <a title="Global index" href="../../genindex.html">Index</a>  |
        <a title="Module index" href="../../py-modindex.html">Modules</a>
      </div>
      <div class="nav">
    &laquo; <a href="middleware.html" title="中间件">previous</a>
     |
    <a href="../index.html" title="使用 Django" accesskey="U">up</a>
   |
    <a href="../forms/index.html" title="使用表单">next</a> &raquo;</div>
    </div>

    <div id="bd">
      <div id="yui-main">
        <div class="yui-b">
          <div class="yui-g" id="topics-http-sessions">
            
  <div class="section" id="s-module-django.contrib.sessions">
<span id="s-how-to-use-sessions"></span><span id="module-django.contrib.sessions"></span><span id="how-to-use-sessions"></span><h1>如何使用会话<a class="headerlink" href="#module-django.contrib.sessions" title="永久链接至标题">¶</a></h1>
<p>Django 是支持匿名会话的。会话框架允许您基于每个站点访问者存储和检索任意数据。它在服务器端存储数据并提供cookie的发送和接收。Cookie包含会话ID - 而不是数据本身（除非您使用基于cookie的后端）。</p>
<div class="section" id="s-enabling-sessions">
<span id="enabling-sessions"></span><h2>打开会话<a class="headerlink" href="#enabling-sessions" title="永久链接至标题">¶</a></h2>
<p>会话通过配置一个中间件实现的</p>
<p>为了打开会话，需要做下面的操作</p>
<ul class="simple">
<li>编辑设置中的 <cite>MIDDLEWARE</cite>，并确保他包含了 <cite>'django.contrib.sessions.middleware.SessionMiddleware'</cite>。通过 <cite>django-admin startproject</cite> 创建的默认 <cite>settings.py</cite> 文件是已经打开了 <cite>SessionMiddleware</cite> 这项设置的。</li>
</ul>
<p>如果你不想使用会话功能，你可以从配置的 <cite>MIDDLEWARE 中删除 `SessionMiddleware</cite>，并且从 <cite>INSTALLED_APPS</cite> 中删除 <cite>'django.contrib.sessions'</cite>。它将会为您节省一点开销。</p>
</div>
<div class="section" id="s-configuring-the-session-engine">
<span id="s-configuring-sessions"></span><span id="configuring-the-session-engine"></span><span id="configuring-sessions"></span><h2>配置会话(session)引擎<a class="headerlink" href="#configuring-the-session-engine" title="永久链接至标题">¶</a></h2>
<p>默认情况下，Django 在数据库里存储会话（使用 <code class="docutils literal notranslate"><span class="pre">django.contrib.sessions.models.Session</span></code> ）。虽然这很方便，但在一些设置里，在其他地方存储会话数据速度更快，因此 Django 可以在文件系统或缓存中配置存储会话数据。</p>
<div class="section" id="s-using-database-backed-sessions">
<span id="using-database-backed-sessions"></span><h3>使用数据库支持的会话<a class="headerlink" href="#using-database-backed-sessions" title="永久链接至标题">¶</a></h3>
<p>如果你想使用数据库支持的会话，你需要在 <a class="reference internal" href="../../ref/settings.html#std:setting-INSTALLED_APPS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">INSTALLED_APPS</span></code></a> 里添加 <code class="docutils literal notranslate"><span class="pre">'django.contrib.sessions'</span></code> 。</p>
<p>一旦在安装中配置，运行 <code class="docutils literal notranslate"><span class="pre">manage.py</span> <span class="pre">migrate</span></code> 来安装单个数据库表来存储会话数据。</p>
</div>
<div class="section" id="s-using-cached-sessions">
<span id="s-cached-sessions-backend"></span><span id="using-cached-sessions"></span><span id="cached-sessions-backend"></span><h3>使用缓存会话<a class="headerlink" href="#using-cached-sessions" title="永久链接至标题">¶</a></h3>
<p>为了得到更好的性能，你可以使用基于缓存的会话后端。</p>
<p>使用 Django 的缓存系统来存储会话，你首先需要确保已经配置了缓存，查看 <a class="reference internal" href="../cache.html"><span class="doc">cache documentation</span></a> 获取详情。</p>
<div class="admonition warning">
<p class="first admonition-title">警告</p>
<p class="last">如果你正在使用 Memcached 缓存后端，则应该只使用基于缓存的会话。本地内存缓存后端保留数据的时间不足以成为一个好的选择，直接使用文件或数据库会话而不是通过文件或数据库缓存后端发送所有内容会更快。另外，本地内存缓存后端并不安全，因此对生产环境来说或许不是一个好的选择。</p>
</div>
<p>如果你在 <a class="reference internal" href="../../ref/settings.html#std:setting-CACHES"><code class="xref std std-setting docutils literal notranslate"><span class="pre">CACHES</span></code></a> 定义了多缓存，Django 会使用默认缓存。如果要使用其他缓存，请将 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_CACHE_ALIAS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_CACHE_ALIAS</span></code></a> 设置为该缓存名。</p>
<p>一旦配置好了缓存，你有两种办法在缓存中存储数据：</p>
<ul class="simple">
<li>设置 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_ENGINE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_ENGINE</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">&quot;django.contrib.sessions.backends.cache&quot;</span></code> 用于简单缓存会话存储。会话数据直接被存储在缓存里。然而，会话数据可能不是长久的：因为缓存满了或者缓存服务重启了，所以缓存数据会被收回。</li>
<li>为了持久化缓存数据，设置 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_ENGINE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_ENGINE</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">&quot;django.contrib.sessions.backends.cached_db&quot;</span></code> 。这使用直写式缓存——每次写入缓存的数据也会被写入到数据库。如果数据不在缓存中，会话仅使用数据库进行读取。</li>
</ul>
<p>这两中会话存储会非常快，但简单缓存会更快，因为它忽略了持久化。在大部分情况下，<code class="docutils literal notranslate"><span class="pre">cached_db</span></code> 后端将足够快，但如果你需要最后一点的性能，并且愿意不时地删除会话数据，那么 <code class="docutils literal notranslate"><span class="pre">cache</span></code> 后端适合你。</p>
<p>如果你使用 <code class="docutils literal notranslate"><span class="pre">cached_db</span></code> 会话后端，你也需要遵循使用数据库支持的会话配置说明( <a class="reference internal" href="#using-database-backed-sessions">using database-backed sessions</a> )。</p>
</div>
<div class="section" id="s-using-file-based-sessions">
<span id="using-file-based-sessions"></span><h3>使用基于文件的会话<a class="headerlink" href="#using-file-based-sessions" title="永久链接至标题">¶</a></h3>
<p>要使用基于文件的会话，需要设置 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_ENGINE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_ENGINE</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">&quot;django.contrib.sessions.backends.file&quot;</span></code> 。</p>
<p>你可能想设置 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_FILE_PATH"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_FILE_PATH</span></code></a> (默认从 <code class="docutils literal notranslate"><span class="pre">tempfile.gettempdir()</span></code> 输出，很可能是 <code class="docutils literal notranslate"><span class="pre">/tmp</span></code> ) 来控制 Django 存储会话文件的路径。要确保 Web 服务器有权限读取这个地址。</p>
</div>
<div class="section" id="s-using-cookie-based-sessions">
<span id="s-cookie-session-backend"></span><span id="using-cookie-based-sessions"></span><span id="cookie-session-backend"></span><h3>使用基于cookie的会话<a class="headerlink" href="#using-cookie-based-sessions" title="永久链接至标题">¶</a></h3>
<p>要使用基于cookies的会话，需要设置 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_ENGINE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_ENGINE</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">&quot;django.contrib.sessions.backends.signed_cookies&quot;</span></code> 。这个会话数据将使用 Django 的加密工具( <a class="reference internal" href="../signing.html"><span class="doc">cryptographic signing</span></a> ) 和 <a class="reference internal" href="../../ref/settings.html#std:setting-SECRET_KEY"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SECRET_KEY</span></code></a> 工具进行保存。</p>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">建议将 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_COOKIE_HTTPONLY"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_COOKIE_HTTPONLY</span></code></a> 设置为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 来防止通过 JavaScript 访问存储数据。</p>
</div>
<div class="admonition warning">
<p class="first admonition-title">警告</p>
<p>如果 SECRET_KEY 泄露了，并且你正在使用 <a class="reference internal" href="#django.contrib.sessions.serializers.PickleSerializer" title="django.contrib.sessions.serializers.PickleSerializer"><code class="xref py py-class docutils literal notranslate"><span class="pre">PickleSerializer</span></code></a> ，这会导致任意远程代码执行。</p>
<p>拥有 <a class="reference internal" href="../../ref/settings.html#std:setting-SECRET_KEY"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SECRET_KEY</span></code></a> 的攻击者不仅可以生成站点信任的伪造会话数据，也可以远程执行任意的代码，因为数据是使用 pickle 序列化的。</p>
<p>如果你使用基于 cookie 的会话，一定要注意对于任何可能远程访问的系统，密钥是完全保密的。</p>
<p><strong>会话数据已签名但未被加密</strong></p>
<p>当使用cookie后端时，会话数据可以被客户端读取。</p>
<p>MAC(消息验证代码) 被用来保护数据不被客户端修改，因此会话数据在被篡改时失效。如果存储cookie 的客户端 (比如浏览器) 不能存储所有会话数据并丢弃数据，则会同样发生失效。即使 Django 压缩数据，它仍然完全有可能每个 cookie 超过4096字节的通用限制（ <span class="target" id="index-2"></span><a class="rfc reference external" href="https://tools.ietf.org/html/rfc2965.html#section-5.3"><strong>common limit of 4096 bytes</strong></a> ）。</p>
<p><strong>不保证新鲜度</strong></p>
<p>注意虽然 MAC 可以保证数据(通过站点生成，而不是其他人)真实性和数据完整(它是完整和正确的)，但它不能保证新鲜度，也就是说，您最后发送给客户端的东西会被退回。这意味着cookie后端为了使用一些会话数据，可能会面临重播攻击。与其他会话后端(每个会话保持服务端记录，并且当用户退出时使会话失效)不同，基于cookie的会话在用户退出的时候并不会让会话失效。因此攻击者窃取用户cookie，即使用户登出了，攻击者还可以使用cookie登录该用户。如果 Cookie 比 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_COOKIE_AGE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_COOKIE_AGE</span></code></a> 设置的时间还旧时，则cookie会被检测为 '陈旧' 。</p>
<p><strong>性能</strong></p>
<p class="last">Finally, the size of a cookie can have an impact on the speed of your site.</p>
</div>
</div>
</div>
<div class="section" id="s-using-sessions-in-views">
<span id="using-sessions-in-views"></span><h2>在视图中使用会话<a class="headerlink" href="#using-sessions-in-views" title="永久链接至标题">¶</a></h2>
<p>当激活 <code class="docutils literal notranslate"><span class="pre">SessionMiddleware</span></code> 后，每个 <a class="reference internal" href="../../ref/request-response.html#django.http.HttpRequest" title="django.http.HttpRequest"><code class="xref py py-class docutils literal notranslate"><span class="pre">HttpRequest</span></code></a> 对象（任何 Django 视图函数的第一个参数） 将得到一个 <code class="docutils literal notranslate"><span class="pre">session</span></code> 属性，该属性是一个类字典对象。</p>
<p>你可以在视图中任意位置读取它并写入 <code class="docutils literal notranslate"><span class="pre">request.session</span></code> 。你可以多次编辑它。</p>
<dl class="class">
<dt id="django.contrib.sessions.backends.base.SessionBase">
<em class="property">class </em><code class="descclassname">backends.base.</code><code class="descname">SessionBase</code><a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase" title="永久链接至目标">¶</a></dt>
<dd><p>这是所有会话对象的基础类。它有以下标准字典方法：</p>
<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.__getitem__">
<code class="descname">__getitem__</code>(<em>key</em>)<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.__getitem__" title="永久链接至目标">¶</a></dt>
<dd><p>比如：<code class="docutils literal notranslate"><span class="pre">fav_color</span> <span class="pre">=</span> <span class="pre">request.session['fav_color']</span></code></p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.__setitem__">
<code class="descname">__setitem__</code>(<em>key</em>, <em>value</em>)<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.__setitem__" title="永久链接至目标">¶</a></dt>
<dd><p>比如：<code class="docutils literal notranslate"><span class="pre">request.session['fav_color']</span> <span class="pre">=</span> <span class="pre">'blue'</span></code></p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.__delitem__">
<code class="descname">__delitem__</code>(<em>key</em>)<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.__delitem__" title="永久链接至目标">¶</a></dt>
<dd><p>比如：<code class="docutils literal notranslate"><span class="pre">del</span> <span class="pre">request.session['fav_color']</span></code> 。如果给定的 <code class="docutils literal notranslate"><span class="pre">key</span></code> 不在会话里，会引发 <code class="docutils literal notranslate"><span class="pre">KeyError</span></code> 。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.__contains__">
<code class="descname">__contains__</code>(<em>key</em>)<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.__contains__" title="永久链接至目标">¶</a></dt>
<dd><p>比如：<code class="docutils literal notranslate"><span class="pre">'fav_color'</span> <span class="pre">in</span> <span class="pre">request.session</span></code></p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.get">
<code class="descname">get</code>(<em>key</em>, <em>default=None</em>)<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.get" title="永久链接至目标">¶</a></dt>
<dd><p>比如：<code class="docutils literal notranslate"><span class="pre">fav_color</span> <span class="pre">=</span> <span class="pre">request.session.get('fav_color',</span> <span class="pre">'red')</span></code></p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.pop">
<code class="descname">pop</code>(<em>key</em>, <em>default=__not_given</em>)<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.pop" title="永久链接至目标">¶</a></dt>
<dd><p>比如：<code class="docutils literal notranslate"><span class="pre">fav_color</span> <span class="pre">=</span> <span class="pre">request.session.pop('fav_color',</span> <span class="pre">'blue')</span></code></p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.keys">
<code class="descname">keys</code>()<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.keys" title="永久链接至目标">¶</a></dt>
<dd></dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.items">
<code class="descname">items</code>()<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.items" title="永久链接至目标">¶</a></dt>
<dd></dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.setdefault">
<code class="descname">setdefault</code>()<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.setdefault" title="永久链接至目标">¶</a></dt>
<dd></dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.clear">
<code class="descname">clear</code>()<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.clear" title="永久链接至目标">¶</a></dt>
<dd></dd></dl>

<p>它也有以下方法：</p>
<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.flush">
<code class="descname">flush</code>()<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.flush" title="永久链接至目标">¶</a></dt>
<dd><p>删除当前会话和会话cookie。如果你想确保早先的会话数据不能被用户的浏览器再次访问时，可以使用这个方法（比如，<a class="reference internal" href="../auth/default.html#django.contrib.auth.logout" title="django.contrib.auth.logout"><code class="xref py py-func docutils literal notranslate"><span class="pre">django.contrib.auth.logout()</span></code></a> 函数调用它）。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.set_test_cookie">
<code class="descname">set_test_cookie</code>()<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.set_test_cookie" title="永久链接至目标">¶</a></dt>
<dd><p>设置一个测试cookie来确定用户的浏览器是否支持cookie。由于测试通过，你不需要在下一个页面请求时再次测试它。查看 <a class="reference internal" href="#setting-test-cookies">Setting test cookies</a> 获取更多信息。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.test_cookie_worked">
<code class="descname">test_cookie_worked</code>()<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.test_cookie_worked" title="永久链接至目标">¶</a></dt>
<dd><p>返回 <code class="docutils literal notranslate"><span class="pre">True</span></code> 或 <code class="docutils literal notranslate"><span class="pre">False</span></code> ，这取决于用户浏览器是否接受测试cookie。由于 cookie 的工作方式，你将必须在上一个独立的页面请求里调用 <code class="docutils literal notranslate"><span class="pre">set_test_cookie()</span></code> 。查看 <a class="reference internal" href="#setting-test-cookies">Setting test cookies</a> 获取更多信息。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.delete_test_cookie">
<code class="descname">delete_test_cookie</code>()<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.delete_test_cookie" title="永久链接至目标">¶</a></dt>
<dd><p>删除测试cookie。使用完测试cookie后用它来删除。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.get_session_cookie_age">
<code class="descname">get_session_cookie_age</code>()<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.get_session_cookie_age" title="永久链接至目标">¶</a></dt>
<dd><p>返回 session cookies的失效时间，以秒为单位。默认 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_COOKIE_AGE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_COOKIE_AGE</span></code></a> 。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.set_expiry">
<code class="descname">set_expiry</code>(<em>value</em>)<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.set_expiry" title="永久链接至目标">¶</a></dt>
<dd><p>为会话设置过期时间。你可以传递很多不同值：</p>
<ul class="simple">
<li>如果 <code class="docutils literal notranslate"><span class="pre">value</span></code> 是整型，会话将在闲置数秒后过期。比如，调用 <code class="docutils literal notranslate"><span class="pre">request.session.set_expiry(300)</span></code> 会使得会话在5分钟后过期。</li>
<li>如果 <code class="docutils literal notranslate"><span class="pre">value</span></code> 是一个 <code class="docutils literal notranslate"><span class="pre">datetime</span></code> 或 <code class="docutils literal notranslate"><span class="pre">timedelta</span></code> 对象，会话将在指定的 date/time 过期。注意，如果你正在使用 <a class="reference internal" href="#django.contrib.sessions.serializers.PickleSerializer" title="django.contrib.sessions.serializers.PickleSerializer"><code class="xref py py-class docutils literal notranslate"><span class="pre">PickleSerializer</span></code></a> ，那么 <code class="docutils literal notranslate"><span class="pre">datetime</span></code> 和 <code class="docutils literal notranslate"><span class="pre">timedelta</span></code> 的值只能序列化。</li>
<li>如果 <code class="docutils literal notranslate"><span class="pre">value</span></code> 是 <code class="docutils literal notranslate"><span class="pre">0</span></code> ，则当浏览器关闭后，用户会话 cookie 将过期。</li>
<li>如果 <code class="docutils literal notranslate"><span class="pre">value</span></code> 是 <code class="docutils literal notranslate"><span class="pre">None</span></code> ，会话会恢复为全局会话过期策略。</li>
</ul>
<p>出于过期目的，读取会话不被视为活动。会话过期时间会在会话最后一次*修改*后开始计算。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.get_expiry_age">
<code class="descname">get_expiry_age</code>()<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.get_expiry_age" title="永久链接至目标">¶</a></dt>
<dd><p>返回该会话过期的秒数。对于没有自定义过期时间的会话（或者那些设置为浏览器关闭时过期的），这等同于 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_COOKIE_AGE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_COOKIE_AGE</span></code></a> 。</p>
<p>这个函数接受两个可选的关键参数：</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">modification</span></code> ：会话的最后一次修改，当做一个 <a class="reference external" href="https://docs.python.org/3/library/datetime.html#datetime.datetime" title="(在 Python v3.10)"><code class="xref py py-class docutils literal notranslate"><span class="pre">datetime</span></code></a> 对象。默认是当前时间。</li>
<li><code class="docutils literal notranslate"><span class="pre">expiry</span></code> ：会话的过期信息，如一个 <a class="reference external" href="https://docs.python.org/3/library/datetime.html#datetime.datetime" title="(在 Python v3.10)"><code class="xref py py-class docutils literal notranslate"><span class="pre">datetime</span></code></a> 对象，整数（秒）或 <code class="docutils literal notranslate"><span class="pre">None</span></code>。默认为通过 <a class="reference internal" href="#django.contrib.sessions.backends.base.SessionBase.set_expiry" title="django.contrib.sessions.backends.base.SessionBase.set_expiry"><code class="xref py py-meth docutils literal notranslate"><span class="pre">set_expiry()</span></code></a> 存储在会话中的值，或 <code class="docutils literal notranslate"><span class="pre">None</span></code> 。</li>
</ul>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.get_expiry_date">
<code class="descname">get_expiry_date</code>()<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.get_expiry_date" title="永久链接至目标">¶</a></dt>
<dd><p>返回该会话的到期日期。对于没有自定义过期的会话(或那些设置为在浏览器关闭时过期的会话)，这将等于从现在开始的SESSION_COOKIE_AGE秒的日期。</p>
<p>这个函数接受与 <a class="reference internal" href="#django.contrib.sessions.backends.base.SessionBase.get_expiry_age" title="django.contrib.sessions.backends.base.SessionBase.get_expiry_age"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_expiry_age()</span></code></a> 相同的参数。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.get_expire_at_browser_close">
<code class="descname">get_expire_at_browser_close</code>()<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.get_expire_at_browser_close" title="永久链接至目标">¶</a></dt>
<dd><p>返回 <code class="docutils literal notranslate"><span class="pre">True</span></code> 或 <code class="docutils literal notranslate"><span class="pre">False</span></code> ，取决于用户会话 cookie 是否在浏览器关闭的时候过期。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.clear_expired">
<code class="descname">clear_expired</code>()<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.clear_expired" title="永久链接至目标">¶</a></dt>
<dd><p>从会话存储中移除过期会话。这个类方法通过 <a class="reference internal" href="../../ref/django-admin.html#django-admin-clearsessions"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">clearsessions</span></code></a> 调用。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.base.SessionBase.cycle_key">
<code class="descname">cycle_key</code>()<a class="headerlink" href="#django.contrib.sessions.backends.base.SessionBase.cycle_key" title="永久链接至目标">¶</a></dt>
<dd><p>在保留当前会话的同时创建新的会话秘钥。<a class="reference internal" href="../auth/default.html#django.contrib.auth.login" title="django.contrib.auth.login"><code class="xref py py-func docutils literal notranslate"><span class="pre">django.contrib.auth.login()</span></code></a> 调用这个方法来防止会话固定攻击。</p>
</dd></dl>

</dd></dl>

<div class="section" id="s-session-serialization">
<span id="s-id1"></span><span id="session-serialization"></span><span id="id1"></span><h3>会话序列化<a class="headerlink" href="#session-serialization" title="永久链接至标题">¶</a></h3>
<p>默认情况下，Django 序列会话数据使用 JSON 。你可以设置 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_SERIALIZER"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_SERIALIZER</span></code></a> 来自定义会话序列化格式。即使在编写你自己的序列化程序中描述了警告，我们仍然强烈建议您坚持JSON序列化，尤其是在您使用cookie后端的情况下。</p>
<p>比如，如果你使用 <a class="reference external" href="https://docs.python.org/3/library/pickle.html#module-pickle" title="(在 Python v3.10)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 来序列化会话数据，那么这里一个攻击场景。如果你正在使用 <a class="reference internal" href="#cookie-session-backend"><span class="std std-ref">signed cookie session backend</span></a> 并且攻击者已经知道了 <a class="reference internal" href="../../ref/settings.html#std:setting-SECRET_KEY"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SECRET_KEY</span></code></a> （Django 并不存在会导致其泄露的固有漏洞），攻击者可以在会话里插入一个字符串，当 unpickled 时，在服务器上执行任意代码。这样做的技术很简单，在互联网上也很容易获得。尽管cookie会话存储会对cookie数据进行签名防止篡改，但是泄露 <a class="reference internal" href="../../ref/settings.html#std:setting-SECRET_KEY"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SECRET_KEY</span></code></a> 会立即升级为远程代码执行的漏洞。</p>
<div class="section" id="s-bundled-serializers">
<span id="bundled-serializers"></span><h4>绑定序列化<a class="headerlink" href="#bundled-serializers" title="永久链接至标题">¶</a></h4>
<dl class="class">
<dt id="django.contrib.sessions.serializers.JSONSerializer">
<em class="property">class </em><code class="descclassname">serializers.</code><code class="descname">JSONSerializer</code><a class="headerlink" href="#django.contrib.sessions.serializers.JSONSerializer" title="永久链接至目标">¶</a></dt>
<dd><p>来自 <a class="reference internal" href="../signing.html#module-django.core.signing" title="django.core.signing: Django's signing framework."><code class="xref py py-mod docutils literal notranslate"><span class="pre">django.core.signing</span></code></a> 的JSON序列化器的装饰器。可以只序列化基本数据类型。</p>
<p>另外，因为JSON只支持字符串键，注意在 <code class="docutils literal notranslate"><span class="pre">request.session</span></code> 使用非字符串键会无法工作：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="c1"># initial assignment</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;bar&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c1"># subsequent requests following serialization &amp; deserialization</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c1"># of session data</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>  <span class="c1"># KeyError</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="s1">&#39;0&#39;</span><span class="p">]</span>
<span class="go">&#39;bar&#39;</span>
</pre></div>
</div>
<p>同样，数据也不能在JSON中编码，例如像 <code class="docutils literal notranslate"><span class="pre">'\xd9'</span></code> 这种非UTF8字节(会引发 <a class="reference external" href="https://docs.python.org/3/library/exceptions.html#UnicodeDecodeError" title="(在 Python v3.10)"><code class="xref py py-exc docutils literal notranslate"><span class="pre">UnicodeDecodeError</span></code></a> )不会被存储。</p>
<p>查看 <a class="reference internal" href="#custom-serializers"><span class="std std-ref">编写自定义的序列化器</span></a> 部分来获取更多有关JSON序列化局限性的内容。</p>
</dd></dl>

<dl class="class">
<dt id="django.contrib.sessions.serializers.PickleSerializer">
<em class="property">class </em><code class="descclassname">serializers.</code><code class="descname">PickleSerializer</code><a class="headerlink" href="#django.contrib.sessions.serializers.PickleSerializer" title="永久链接至目标">¶</a></dt>
<dd><p>支持任何Python对象，但是，如上所述，如果 <a class="reference internal" href="../../ref/settings.html#std:setting-SECRET_KEY"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SECRET_KEY</span></code></a> 泄露，这会导致攻击者执行远程代码的漏洞。</p>
</dd></dl>

</div>
<div class="section" id="s-write-your-own-serializer">
<span id="s-custom-serializers"></span><span id="write-your-own-serializer"></span><span id="custom-serializers"></span><h4>编写自定义的序列化器<a class="headerlink" href="#write-your-own-serializer" title="永久链接至标题">¶</a></h4>
<p>注意这与 <a class="reference internal" href="#django.contrib.sessions.serializers.PickleSerializer" title="django.contrib.sessions.serializers.PickleSerializer"><code class="xref py py-class docutils literal notranslate"><span class="pre">PickleSerializer</span></code></a> 不同，<a class="reference internal" href="#django.contrib.sessions.serializers.JSONSerializer" title="django.contrib.sessions.serializers.JSONSerializer"><code class="xref py py-class docutils literal notranslate"><span class="pre">JSONSerializer</span></code></a> 不会处理任何Python数据类型。通常情况下，便利性和安全性之间要做出权衡取舍。如果你想在 JSON 支持的会话里存储任何高级数据类型(比如 <code class="docutils literal notranslate"><span class="pre">datetime</span></code> 和 <code class="docutils literal notranslate"><span class="pre">Decimal</span></code> )，你需要编写自己的序列化器(或者在存储这类值到 <code class="docutils literal notranslate"><span class="pre">request.session</span></code> 之前把它们转化JSON序列化类型)。虽然序列化这些值通常很简单( <a class="reference internal" href="../serialization.html#django.core.serializers.json.DjangoJSONEncoder" title="django.core.serializers.json.DjangoJSONEncoder"><code class="xref py py-class docutils literal notranslate"><span class="pre">DjangoJSONEncoder</span></code></a> 或许有帮助)，但编写一个解码器来可靠地取回你放进去的东西就更不容易了。 例如，你要返回一个字符串格式的 <code class="docutils literal notranslate"><span class="pre">datetime</span></code> ，但这恰好与为 <code class="docutils literal notranslate"><span class="pre">datetime</span></code> s 选择的格式相同，这样会有风险。</p>
<p>你的序列化类必须实现两个方法( <code class="docutils literal notranslate"><span class="pre">dumps(self,</span> <span class="pre">obj)</span></code> 和 <code class="docutils literal notranslate"><span class="pre">loads(self,</span> <span class="pre">data)</span></code> ) 来分别进行序列化和反序列化会话数据字典。</p>
</div>
</div>
<div class="section" id="s-session-object-guidelines">
<span id="session-object-guidelines"></span><h3>会话对象指南<a class="headerlink" href="#session-object-guidelines" title="永久链接至标题">¶</a></h3>
<ul class="simple">
<li>在  <code class="docutils literal notranslate"><span class="pre">request.session</span></code> 上使用普通的 Python 字符串作为字典键。这更多的是一种惯例而不是硬性规定。</li>
<li>以下划线开头的会话字典键保留给 Django 作内部使用。</li>
<li>不要使用新对象覆盖 <code class="docutils literal notranslate"><span class="pre">request.session</span></code> ，不要访问或设置它的属性。像使用 Python 字典一样使用它。</li>
</ul>
</div>
<div class="section" id="s-examples">
<span id="examples"></span><h3>示例<a class="headerlink" href="#examples" title="永久链接至标题">¶</a></h3>
<p>这个简单的视图将一个 <code class="docutils literal notranslate"><span class="pre">has_commented</span></code> 变量在用户评论后设置为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 。它不允许用户发表评论多于一次：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">post_comment</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">new_comment</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;has_commented&#39;</span><span class="p">,</span> <span class="kc">False</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">HttpResponse</span><span class="p">(</span><span class="s2">&quot;You&#39;ve already commented.&quot;</span><span class="p">)</span>
    <span class="n">c</span> <span class="o">=</span> <span class="n">comments</span><span class="o">.</span><span class="n">Comment</span><span class="p">(</span><span class="n">comment</span><span class="o">=</span><span class="n">new_comment</span><span class="p">)</span>
    <span class="n">c</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
    <span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="s1">&#39;has_commented&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
    <span class="k">return</span> <span class="n">HttpResponse</span><span class="p">(</span><span class="s1">&#39;Thanks for your comment!&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>这是一个记录站点成员的简单的视图。</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">login</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="n">m</span> <span class="o">=</span> <span class="n">Member</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">[</span><span class="s1">&#39;username&#39;</span><span class="p">])</span>
    <span class="k">if</span> <span class="n">m</span><span class="o">.</span><span class="n">password</span> <span class="o">==</span> <span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">[</span><span class="s1">&#39;password&#39;</span><span class="p">]:</span>
        <span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="s1">&#39;member_id&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">m</span><span class="o">.</span><span class="n">id</span>
        <span class="k">return</span> <span class="n">HttpResponse</span><span class="p">(</span><span class="s2">&quot;You&#39;re logged in.&quot;</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">HttpResponse</span><span class="p">(</span><span class="s2">&quot;Your username and password didn&#39;t match.&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>这是记录成员退出的视图：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">logout</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">del</span> <span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="s1">&#39;member_id&#39;</span><span class="p">]</span>
    <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
        <span class="k">pass</span>
    <span class="k">return</span> <span class="n">HttpResponse</span><span class="p">(</span><span class="s2">&quot;You&#39;re logged out.&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>标准的 <a class="reference internal" href="../auth/default.html#django.contrib.auth.logout" title="django.contrib.auth.logout"><code class="xref py py-meth docutils literal notranslate"><span class="pre">django.contrib.auth.logout()</span></code></a> 函数实际上比这里要多一些来防止数据意外泄露。它调用 <code class="docutils literal notranslate"><span class="pre">request.session</span></code> 的 <a class="reference internal" href="#django.contrib.sessions.backends.base.SessionBase.flush" title="django.contrib.sessions.backends.base.SessionBase.flush"><code class="xref py py-meth docutils literal notranslate"><span class="pre">flush()</span></code></a> 方法。我们使用这个例子作为示范如何使用会话对象，而不是完整的 <code class="docutils literal notranslate"><span class="pre">logout()</span></code> 实现。</p>
</div>
</div>
<div class="section" id="s-setting-test-cookies">
<span id="setting-test-cookies"></span><h2>测试 <code class="docutils literal notranslate"><span class="pre">cookies</span></code> 设置<a class="headerlink" href="#setting-test-cookies" title="永久链接至标题">¶</a></h2>
<p>为了方便起见，Django 提供一种方法来测试用户浏览器是否支持cookies。调用视图里 <code class="docutils literal notranslate"><span class="pre">request.session</span></code> 的 <a class="reference internal" href="#django.contrib.sessions.backends.base.SessionBase.set_test_cookie" title="django.contrib.sessions.backends.base.SessionBase.set_test_cookie"><code class="xref py py-meth docutils literal notranslate"><span class="pre">set_test_cookie()</span></code></a> 方法，并且在后续视图里调用 <a class="reference internal" href="#django.contrib.sessions.backends.base.SessionBase.test_cookie_worked" title="django.contrib.sessions.backends.base.SessionBase.test_cookie_worked"><code class="xref py py-meth docutils literal notranslate"><span class="pre">test_cookie_worked()</span></code></a> —— 不是在同一个视图里调用。</p>
<p>由于 cookies 的工作方式， <code class="docutils literal notranslate"><span class="pre">set_test_cookie()</span></code> 和 <code class="docutils literal notranslate"><span class="pre">test_cookie_worked()</span></code> 之间尴尬的分割是有必要的。当你设置了一个 cookie，在浏览器的下一个请求之前，实际上你不能判断浏览器是否接受它。</p>
<p>使用 <a class="reference internal" href="#django.contrib.sessions.backends.base.SessionBase.delete_test_cookie" title="django.contrib.sessions.backends.base.SessionBase.delete_test_cookie"><code class="xref py py-meth docutils literal notranslate"><span class="pre">delete_test_cookie()</span></code></a> 来清理是个好习惯。在验证测试的 cookie 可用之后来执行它。</p>
<p>这里是一个典型的用法示例：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">HttpResponse</span>
<span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">render</span>

<span class="k">def</span> <span class="nf">login</span><span class="p">(</span><span class="n">request</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">&#39;POST&#39;</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">test_cookie_worked</span><span class="p">():</span>
            <span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">delete_test_cookie</span><span class="p">()</span>
            <span class="k">return</span> <span class="n">HttpResponse</span><span class="p">(</span><span class="s2">&quot;You&#39;re logged in.&quot;</span><span class="p">)</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">HttpResponse</span><span class="p">(</span><span class="s2">&quot;Please enable cookies and try again.&quot;</span><span class="p">)</span>
    <span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">set_test_cookie</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">&#39;foo/login_form.html&#39;</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="s-using-sessions-out-of-views">
<span id="using-sessions-out-of-views"></span><h2>在视图外使用会话<a class="headerlink" href="#using-sessions-out-of-views" title="永久链接至标题">¶</a></h2>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p>这部分的例子直接从 <code class="docutils literal notranslate"><span class="pre">django.contrib.sessions.backends.db</span></code> 后端导入 <code class="docutils literal notranslate"><span class="pre">SessionStore</span></code> 对象。在你自己的代码里，你应该考虑从 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_ENGINE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_ENGINE</span></code></a> 指定的会话引擎导入 <code class="docutils literal notranslate"><span class="pre">SessionStore</span></code> 。</p>
<div class="last highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">importlib</span> <span class="kn">import</span> <span class="n">import_module</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">SessionStore</span> <span class="o">=</span> <span class="n">import_module</span><span class="p">(</span><span class="n">settings</span><span class="o">.</span><span class="n">SESSION_ENGINE</span><span class="p">)</span><span class="o">.</span><span class="n">SessionStore</span>
</pre></div>
</div>
</div>
<p>可以在视图外对会话数据进行操作的 API ：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">django.contrib.sessions.backends.db</span> <span class="kn">import</span> <span class="n">SessionStore</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span> <span class="o">=</span> <span class="n">SessionStore</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c1"># stored as seconds since epoch since datetimes are not serializable in JSON.</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span><span class="p">[</span><span class="s1">&#39;last_login&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1376587691</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span><span class="o">.</span><span class="n">create</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span><span class="o">.</span><span class="n">session_key</span>
<span class="go">&#39;2b1189a188b44ad18c35e113ac6ceead&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span> <span class="o">=</span> <span class="n">SessionStore</span><span class="p">(</span><span class="n">session_key</span><span class="o">=</span><span class="s1">&#39;2b1189a188b44ad18c35e113ac6ceead&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span><span class="p">[</span><span class="s1">&#39;last_login&#39;</span><span class="p">]</span>
<span class="go">1376587691</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">SessionStore.create()</span></code> 用来创建一个新会话（即不从会话中加载，并带有 <code class="docutils literal notranslate"><span class="pre">session_key=None</span></code>）。<code class="docutils literal notranslate"><span class="pre">save()</span></code> 用来保存已存在的会话（即从会话存储中加载）。在新会话上调用 <code class="docutils literal notranslate"><span class="pre">save()</span></code> 也许会工作，但生成与现有会话相冲突的 <code class="docutils literal notranslate"><span class="pre">session_key</span></code> 的概率很小。<code class="docutils literal notranslate"><span class="pre">create()</span></code> 调用 <code class="docutils literal notranslate"><span class="pre">save()</span></code> 并循环，直到生成了未使用过的 <code class="docutils literal notranslate"><span class="pre">session_key</span></code> 。</p>
<p>如果你正在使用 <code class="docutils literal notranslate"><span class="pre">django.contrib.sessions.backends.db</span></code> 后端，每个会话就会是一个普通的 Django 模型。 <code class="docutils literal notranslate"><span class="pre">Session</span></code> 模型在 <code class="docutils literal notranslate"><span class="pre">django/contrib/sessions/models.py</span></code> 中定义。因为它就是一个普通模型，你可以使用普通的 Django 数据库 API 访问会话。</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">django.contrib.sessions.models</span> <span class="kn">import</span> <span class="n">Session</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span> <span class="o">=</span> <span class="n">Session</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pk</span><span class="o">=</span><span class="s1">&#39;2b1189a188b44ad18c35e113ac6ceead&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span><span class="o">.</span><span class="n">expire_date</span>
<span class="go">datetime.datetime(2005, 8, 20, 13, 35, 12)</span>
</pre></div>
</div>
<p>注意你将需要调用 <a class="reference internal" href="#django.contrib.sessions.base_session.AbstractBaseSession.get_decoded" title="django.contrib.sessions.base_session.AbstractBaseSession.get_decoded"><code class="xref py py-meth docutils literal notranslate"><span class="pre">get_decoded()</span></code></a> 来得到会话字典。这是必须的，因为字典是按照编码格式存储的：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">s</span><span class="o">.</span><span class="n">session_data</span>
<span class="go">&#39;KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span><span class="o">.</span><span class="n">get_decoded</span><span class="p">()</span>
<span class="go">{&#39;user_id&#39;: 42}</span>
</pre></div>
</div>
</div>
<div class="section" id="s-when-sessions-are-saved">
<span id="when-sessions-are-saved"></span><h2>当保存会话时<a class="headerlink" href="#when-sessions-are-saved" title="永久链接至标题">¶</a></h2>
<p>默认情况下，Django 只在会话被修改后才会向会话数据库保存会话——也就是说，是否已经分配或删除了它的任何字典值：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Session is modified.</span>
<span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="s1">&#39;foo&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;bar&#39;</span>

<span class="c1"># Session is modified.</span>
<span class="k">del</span> <span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="s1">&#39;foo&#39;</span><span class="p">]</span>

<span class="c1"># Session is modified.</span>
<span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="s1">&#39;foo&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>

<span class="c1"># Gotcha: Session is NOT modified, because this alters</span>
<span class="c1"># request.session[&#39;foo&#39;] instead of request.session.</span>
<span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="s1">&#39;foo&#39;</span><span class="p">][</span><span class="s1">&#39;bar&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;baz&#39;</span>
</pre></div>
</div>
<p>在上面例子的最后一个例子中，我们可以通过在会话对象上设置 <code class="docutils literal notranslate"><span class="pre">modified</span></code> 属性来明确地告诉会话对象它已经被修改：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">request</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">modified</span> <span class="o">=</span> <span class="kc">True</span>
</pre></div>
</div>
<p>要想改变这个默认行为，可以设置 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_SAVE_EVERY_REQUEST"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_SAVE_EVERY_REQUEST</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 。当设置为 <code class="docutils literal notranslate"><span class="pre">True</span></code> 时，Django 会根据每个请求将会话保存到数据库中。</p>
<p>注意，仅在会话被创建或修改时发送会话 cookie 。如果 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_SAVE_EVERY_REQUEST"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_SAVE_EVERY_REQUEST</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">True</span></code> ，则会话cookie将在每次请求时发送。</p>
<p>同样地，每次发送会话 cookie 时都会更新会话 cookie 的 <code class="docutils literal notranslate"><span class="pre">expires</span></code> 部分。</p>
<p>如果响应状态代码为 500，会话不会被保存。</p>
</div>
<div class="section" id="s-browser-length-sessions-vs-persistent-sessions">
<span id="s-browser-length-vs-persistent-sessions"></span><span id="browser-length-sessions-vs-persistent-sessions"></span><span id="browser-length-vs-persistent-sessions"></span><h2>Browser-length 会话 vs 持久会话<a class="headerlink" href="#browser-length-sessions-vs-persistent-sessions" title="永久链接至标题">¶</a></h2>
<p>你可以通过设置 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_EXPIRE_AT_BROWSER_CLOSE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_EXPIRE_AT_BROWSER_CLOSE</span></code></a> 来控制会话框架是使用 browser-length 会话还是持久会话。</p>
<p>默认情况下， <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_EXPIRE_AT_BROWSER_CLOSE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_EXPIRE_AT_BROWSER_CLOSE</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">False</span></code> ，这意味着会话 cookies 将保存在用户浏览器中持续 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_COOKIE_AGE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_COOKIE_AGE</span></code></a> 的时间。如果你不想用户每次打开浏览器时必须登录，就用这个。</p>
<p>如果 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_EXPIRE_AT_BROWSER_CLOSE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_EXPIRE_AT_BROWSER_CLOSE</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">True</span></code>，Django 将使用 browser-length cookies —— cookies 在用户关闭浏览器时过期。如果你想让用户每次打开浏览器时必须登录，就用这个。</p>
<p>这个设置是全局默认的，并且可以通过显式调用 <code class="docutils literal notranslate"><span class="pre">request.session</span></code>  的 <a class="reference internal" href="#django.contrib.sessions.backends.base.SessionBase.set_expiry" title="django.contrib.sessions.backends.base.SessionBase.set_expiry"><code class="xref py py-meth docutils literal notranslate"><span class="pre">set_expiry()</span></code></a> 在每个会话级别上覆盖，和之前的 <a class="reference internal" href="#using-sessions-in-views">using sessions in views</a> 里描述的一样。</p>
<div class="admonition note">
<p class="first admonition-title">注解</p>
<p class="last">有一些浏览器（比如谷歌浏览器）提供允许用户在关闭或重新打开浏览器后继续浏览会话的设置。有时候，这会妨碍 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_EXPIRE_AT_BROWSER_CLOSE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_EXPIRE_AT_BROWSER_CLOSE</span></code></a> 设置，并且阻止会话在浏览器关闭时过期。如果开启了 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_EXPIRE_AT_BROWSER_CLOSE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_EXPIRE_AT_BROWSER_CLOSE</span></code></a> 设置，在测试 Django 程序时要注意这一点。</p>
</div>
</div>
<div class="section" id="s-clearing-the-session-store">
<span id="s-id2"></span><span id="clearing-the-session-store"></span><span id="id2"></span><h2>清除会话存储<a class="headerlink" href="#clearing-the-session-store" title="永久链接至标题">¶</a></h2>
<p>当用户创建了新会话，会话数据会累积在会话存储中。如果你正在使用数据库后端，<code class="docutils literal notranslate"><span class="pre">django_session</span></code> 数据库表会增加。如果你使用的是文件后端，临时目录会包含新增加的文件。</p>
<p>为了理解这个问题，要考虑数据库后端会发生什么。当用户登录时，Django 在 <code class="docutils literal notranslate"><span class="pre">django_session</span></code> 增加了一行。每次会话更改时，Django 会更新该行。如果用户手动退出，Django 会删除该行。但如果用户不退出，该行就不会被删除。文件后端也是类似的处理。</p>
<p>Django 没有提供过期会话自动清除的功能。因此，你需要定期清除过期会话。Django 提供了一个清除管理命令：<a class="reference internal" href="../../ref/django-admin.html#django-admin-clearsessions"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">clearsessions</span></code></a> 。推荐在定期清除时使用该命令，例如在日常的定时任务中。</p>
<p>注意缓存后端不受此问题的影响，因为缓存会自动删除过期数据。cookie 后端也一样，因为会话数据通过浏览器存储。</p>
</div>
<div class="section" id="s-settings">
<span id="settings"></span><h2>配置<a class="headerlink" href="#settings" title="永久链接至标题">¶</a></h2>
<p>一些可以用来控制会话行为的 <a class="reference internal" href="../../ref/settings.html#settings-sessions"><span class="std std-ref">Django settings</span></a> ：</p>
<ul class="simple">
<li><a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_CACHE_ALIAS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_CACHE_ALIAS</span></code></a></li>
<li><a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_COOKIE_AGE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_COOKIE_AGE</span></code></a></li>
<li><a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_COOKIE_DOMAIN"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_COOKIE_DOMAIN</span></code></a></li>
<li><a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_COOKIE_HTTPONLY"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_COOKIE_HTTPONLY</span></code></a></li>
<li><a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_COOKIE_NAME"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_COOKIE_NAME</span></code></a></li>
<li><a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_COOKIE_PATH"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_COOKIE_PATH</span></code></a></li>
<li><a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_COOKIE_SAMESITE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_COOKIE_SAMESITE</span></code></a></li>
<li><a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_COOKIE_SECURE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_COOKIE_SECURE</span></code></a></li>
<li><a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_ENGINE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_ENGINE</span></code></a></li>
<li><a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_EXPIRE_AT_BROWSER_CLOSE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_EXPIRE_AT_BROWSER_CLOSE</span></code></a></li>
<li><a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_FILE_PATH"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_FILE_PATH</span></code></a></li>
<li><a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_SAVE_EVERY_REQUEST"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_SAVE_EVERY_REQUEST</span></code></a></li>
<li><a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_SERIALIZER"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_SERIALIZER</span></code></a></li>
</ul>
</div>
<div class="section" id="s-session-security">
<span id="s-topics-session-security"></span><span id="session-security"></span><span id="topics-session-security"></span><h2>会话安全<a class="headerlink" href="#session-security" title="永久链接至标题">¶</a></h2>
<p>站点内的子域可以在客户端上为整个域设置 cookies。如果 cookies 允许来自不受新人用户控制的子域，这将使会话固定成为可能。</p>
<p>比如，一个攻击者登入了 <code class="docutils literal notranslate"><span class="pre">good.example.com</span></code> 并且为账户获得了一个有效会话。如果攻击者控制了 <code class="docutils literal notranslate"><span class="pre">bad.example.com</span></code> ，他们可以使用它来发送他们的会话秘钥给你（会话秘钥是保证用户跟其它计算机或者两台计算机之间安全通信会话而随机产生的加密和解密密钥），因为子域已经允许在 <code class="docutils literal notranslate"><span class="pre">*.example.com</span></code> 上设置 cookies 。</p>
<p>另一个可能的攻击是如果 <code class="docutils literal notranslate"><span class="pre">good.example.com</span></code> 设置它的 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_COOKIE_DOMAIN"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_COOKIE_DOMAIN</span></code></a> 为 <code class="docutils literal notranslate"><span class="pre">&quot;example.com&quot;</span></code> ，会导致来自站点的会话 cookies 发送到 <code class="docutils literal notranslate"><span class="pre">bad.example.com</span></code> 。</p>
</div>
<div class="section" id="s-technical-details">
<span id="technical-details"></span><h2>技术细节<a class="headerlink" href="#technical-details" title="永久链接至标题">¶</a></h2>
<ul class="simple">
<li>该会话目录在使用 <a class="reference internal" href="#django.contrib.sessions.serializers.JSONSerializer" title="django.contrib.sessions.serializers.JSONSerializer"><code class="xref py py-class docutils literal notranslate"><span class="pre">JSONSerializer</span></code></a> 时接受任何 <a class="reference external" href="https://docs.python.org/3/library/json.html#module-json" title="(在 Python v3.10)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">json</span></code></a> 序列化值或者当使用 <a class="reference internal" href="#django.contrib.sessions.serializers.PickleSerializer" title="django.contrib.sessions.serializers.PickleSerializer"><code class="xref py py-class docutils literal notranslate"><span class="pre">PickleSerializer</span></code></a> 时接受任何 picklable Python对象。查看 <a class="reference external" href="https://docs.python.org/3/library/pickle.html#module-pickle" title="(在 Python v3.10)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> 模块获取更多信息。</li>
<li>会话数据保存在名为 <code class="docutils literal notranslate"><span class="pre">django_session</span></code> 的数据库表中。</li>
<li>Django 只有它需要的时候才会发送 cookie 。如果你不想设置任何会话数据，它将不会发送会话 cookie 。</li>
</ul>
<div class="section" id="s-the-sessionstore-object">
<span id="the-sessionstore-object"></span><h3><code class="docutils literal notranslate"><span class="pre">SessionStore</span></code> 对象<a class="headerlink" href="#the-sessionstore-object" title="永久链接至标题">¶</a></h3>
<p>当内部使用会话时，Django 使用来自相应会话引擎的会话存储对象。按照惯例，会话存储对象类名为 <code class="docutils literal notranslate"><span class="pre">SessionStore</span></code> ，并且位于 <a class="reference internal" href="../../ref/settings.html#std:setting-SESSION_ENGINE"><code class="xref std std-setting docutils literal notranslate"><span class="pre">SESSION_ENGINE</span></code></a> 的模块中。</p>
<p>所有 <code class="docutils literal notranslate"><span class="pre">SessionStore</span></code> 类继承了 <a class="reference internal" href="#django.contrib.sessions.backends.base.SessionBase" title="django.contrib.sessions.backends.base.SessionBase"><code class="xref py py-class docutils literal notranslate"><span class="pre">SessionBase</span></code></a> 并且实现了数据操作方法，即：</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">exists()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">create()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">save()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">delete()</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">load()</span></code></li>
<li><a class="reference internal" href="#django.contrib.sessions.backends.base.SessionBase.clear_expired" title="django.contrib.sessions.backends.base.SessionBase.clear_expired"><code class="xref py py-meth docutils literal notranslate"><span class="pre">clear_expired()</span></code></a></li>
</ul>
<p>为了搭建自定义的会话引擎或自定义已有的引擎，你可以创建一个继承自 <a class="reference internal" href="#django.contrib.sessions.backends.base.SessionBase" title="django.contrib.sessions.backends.base.SessionBase"><code class="xref py py-class docutils literal notranslate"><span class="pre">SessionBase</span></code></a> 的新类或任何其他已存在的 <code class="docutils literal notranslate"><span class="pre">SessionStore</span></code> 类。</p>
<p>你可以扩展会话引擎，但对于使用数据库支持的会话引擎通常需要额外的功夫（查看下节来获取更多详情）。</p>
</div>
</div>
<div class="section" id="s-extending-database-backed-session-engines">
<span id="s-id3"></span><span id="extending-database-backed-session-engines"></span><span id="id3"></span><h2>扩展数据库支持的会话引擎<a class="headerlink" href="#extending-database-backed-session-engines" title="永久链接至标题">¶</a></h2>
<p>可以通过继承 <a class="reference internal" href="#django.contrib.sessions.base_session.AbstractBaseSession" title="django.contrib.sessions.base_session.AbstractBaseSession"><code class="xref py py-class docutils literal notranslate"><span class="pre">AbstractBaseSession</span></code></a> 和 <code class="docutils literal notranslate"><span class="pre">SessionStore``类来创建基于Django中包含的自定义数据库支持的会话引擎(即</span> <span class="pre">``db</span></code> 和 <code class="docutils literal notranslate"><span class="pre">cached_db</span></code> )。</p>
<p><code class="docutils literal notranslate"><span class="pre">AbstractBaseSession</span></code> 和 <code class="docutils literal notranslate"><span class="pre">BaseSessionManager</span></code> 可以从 <code class="docutils literal notranslate"><span class="pre">django.contrib.sessions.base_session</span></code> 导入，因此它们可以在  <a class="reference internal" href="../../ref/settings.html#std:setting-INSTALLED_APPS"><code class="xref std std-setting docutils literal notranslate"><span class="pre">INSTALLED_APPS</span></code></a> 不包含 <code class="docutils literal notranslate"><span class="pre">django.contrib.sessions</span></code> 的情况下导入。</p>
<dl class="class">
<dt id="django.contrib.sessions.base_session.AbstractBaseSession">
<em class="property">class </em><code class="descclassname">base_session.</code><code class="descname">AbstractBaseSession</code><a class="headerlink" href="#django.contrib.sessions.base_session.AbstractBaseSession" title="永久链接至目标">¶</a></dt>
<dd><p>抽象基本会话模型。</p>
<dl class="attribute">
<dt id="django.contrib.sessions.base_session.AbstractBaseSession.session_key">
<code class="descname">session_key</code><a class="headerlink" href="#django.contrib.sessions.base_session.AbstractBaseSession.session_key" title="永久链接至目标">¶</a></dt>
<dd><p>主键。字段本身可能包含多达40个字符。当前实现生成一个32个字符的字符串（一个随机的数字序列和小写的ascii字母）。</p>
</dd></dl>

<dl class="attribute">
<dt id="django.contrib.sessions.base_session.AbstractBaseSession.session_data">
<code class="descname">session_data</code><a class="headerlink" href="#django.contrib.sessions.base_session.AbstractBaseSession.session_data" title="永久链接至目标">¶</a></dt>
<dd><p>包含编码和序列化会话字典的字符串。</p>
</dd></dl>

<dl class="attribute">
<dt id="django.contrib.sessions.base_session.AbstractBaseSession.expire_date">
<code class="descname">expire_date</code><a class="headerlink" href="#django.contrib.sessions.base_session.AbstractBaseSession.expire_date" title="永久链接至目标">¶</a></dt>
<dd><p>指定会话何时到期的日期时间。</p>
<p>但是，过期的会话对用户不可用，但在运行 <a class="reference internal" href="../../ref/django-admin.html#django-admin-clearsessions"><code class="xref std std-djadmin docutils literal notranslate"><span class="pre">clearsessions</span></code></a> 管理命令之前，它们仍可能存储在数据库中。</p>
</dd></dl>

<dl class="classmethod">
<dt id="django.contrib.sessions.base_session.AbstractBaseSession.get_session_store_class">
<em class="property">classmethod </em><code class="descname">get_session_store_class</code>()<a class="headerlink" href="#django.contrib.sessions.base_session.AbstractBaseSession.get_session_store_class" title="永久链接至目标">¶</a></dt>
<dd><p>返回要与此会话模型一起使用的会话存储类。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.base_session.AbstractBaseSession.get_decoded">
<code class="descname">get_decoded</code>()<a class="headerlink" href="#django.contrib.sessions.base_session.AbstractBaseSession.get_decoded" title="永久链接至目标">¶</a></dt>
<dd><p>返回解码的会话数据。</p>
<p>解码由会话存储类执行。</p>
</dd></dl>

</dd></dl>

<p>还可以通过子类 <a class="reference internal" href="#django.contrib.sessions.base_session.BaseSessionManager" title="django.contrib.sessions.base_session.BaseSessionManager"><code class="xref py py-class docutils literal notranslate"><span class="pre">BaseSessionManager</span></code></a> 自定义模型管理器。</p>
<dl class="class">
<dt id="django.contrib.sessions.base_session.BaseSessionManager">
<em class="property">class </em><code class="descclassname">base_session.</code><code class="descname">BaseSessionManager</code><a class="headerlink" href="#django.contrib.sessions.base_session.BaseSessionManager" title="永久链接至目标">¶</a></dt>
<dd><dl class="method">
<dt id="django.contrib.sessions.base_session.BaseSessionManager.encode">
<code class="descname">encode</code>(<em>session_dict</em>)<a class="headerlink" href="#django.contrib.sessions.base_session.BaseSessionManager.encode" title="永久链接至目标">¶</a></dt>
<dd><p>返回序列化并编码为字符串的给定会话字典。</p>
<p>编码由绑定到模型类的会话存储类执行。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.base_session.BaseSessionManager.save">
<code class="descname">save</code>(<em>session_key</em>, <em>session_dict</em>, <em>expire_date</em>)<a class="headerlink" href="#django.contrib.sessions.base_session.BaseSessionManager.save" title="永久链接至目标">¶</a></dt>
<dd><p>为提供的会话密钥保存会话数据，或在数据为空时删除会话。</p>
</dd></dl>

</dd></dl>

<p>通过重写以下描述的方法和属性，实现了 <code class="docutils literal notranslate"><span class="pre">SessionStore</span></code> 类的定制：</p>
<dl class="class">
<dt id="django.contrib.sessions.backends.db.SessionStore">
<em class="property">class </em><code class="descclassname">backends.db.</code><code class="descname">SessionStore</code><a class="headerlink" href="#django.contrib.sessions.backends.db.SessionStore" title="永久链接至目标">¶</a></dt>
<dd><p>实现数据库支持的会话存储。</p>
<dl class="classmethod">
<dt id="django.contrib.sessions.backends.db.SessionStore.get_model_class">
<em class="property">classmethod </em><code class="descname">get_model_class</code>()<a class="headerlink" href="#django.contrib.sessions.backends.db.SessionStore.get_model_class" title="永久链接至目标">¶</a></dt>
<dd><p>如果需要的话，重写此方法以返回自定义会话模型。</p>
</dd></dl>

<dl class="method">
<dt id="django.contrib.sessions.backends.db.SessionStore.create_model_instance">
<code class="descname">create_model_instance</code>(<em>data</em>)<a class="headerlink" href="#django.contrib.sessions.backends.db.SessionStore.create_model_instance" title="永久链接至目标">¶</a></dt>
<dd><p>返回会话模型对象的新实例，该实例表示当前会话状态。</p>
<p>重写此方法提供了在将会话模型数据保存到数据库之前修改它的能力。</p>
</dd></dl>

</dd></dl>

<dl class="class">
<dt id="django.contrib.sessions.backends.cached_db.SessionStore">
<em class="property">class </em><code class="descclassname">backends.cached_db.</code><code class="descname">SessionStore</code><a class="headerlink" href="#django.contrib.sessions.backends.cached_db.SessionStore" title="永久链接至目标">¶</a></dt>
<dd><p>实现缓存数据库支持的会话存储。</p>
<dl class="attribute">
<dt id="django.contrib.sessions.backends.cached_db.SessionStore.cache_key_prefix">
<code class="descname">cache_key_prefix</code><a class="headerlink" href="#django.contrib.sessions.backends.cached_db.SessionStore.cache_key_prefix" title="永久链接至目标">¶</a></dt>
<dd><p>添加到会话键中以生成缓存键字符串的前缀。</p>
</dd></dl>

</dd></dl>

<div class="section" id="s-example">
<span id="example"></span><h3>例如<a class="headerlink" href="#example" title="永久链接至标题">¶</a></h3>
<p>下面的示例显示了一个自定义数据库支持的会话引擎，它包括一个用于存储帐户id的附加数据库列（从而提供了一个选项，用于查询数据库中帐户的所有活动会话）：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.contrib.sessions.backends.db</span> <span class="kn">import</span> <span class="n">SessionStore</span> <span class="k">as</span> <span class="n">DBStore</span>
<span class="kn">from</span> <span class="nn">django.contrib.sessions.base_session</span> <span class="kn">import</span> <span class="n">AbstractBaseSession</span>
<span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>

<span class="k">class</span> <span class="nc">CustomSession</span><span class="p">(</span><span class="n">AbstractBaseSession</span><span class="p">):</span>
    <span class="n">account_id</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">(</span><span class="n">null</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">db_index</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>

    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">get_session_store_class</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">SessionStore</span>

<span class="k">class</span> <span class="nc">SessionStore</span><span class="p">(</span><span class="n">DBStore</span><span class="p">):</span>
    <span class="nd">@classmethod</span>
    <span class="k">def</span> <span class="nf">get_model_class</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">CustomSession</span>

    <span class="k">def</span> <span class="nf">create_model_instance</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
        <span class="n">obj</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">create_model_instance</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">account_id</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;_auth_user_id&#39;</span><span class="p">))</span>
        <span class="k">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">TypeError</span><span class="p">):</span>
            <span class="n">account_id</span> <span class="o">=</span> <span class="kc">None</span>
        <span class="n">obj</span><span class="o">.</span><span class="n">account_id</span> <span class="o">=</span> <span class="n">account_id</span>
        <span class="k">return</span> <span class="n">obj</span>
</pre></div>
</div>
<p>如果要从Django的内置 <code class="docutils literal notranslate"><span class="pre">cached_db</span></code> 会话存储迁移到基于``cached_db`` 的自定义存储，则应重写缓存键前缀，以防止名称空间冲突：</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">SessionStore</span><span class="p">(</span><span class="n">CachedDBStore</span><span class="p">):</span>
    <span class="n">cache_key_prefix</span> <span class="o">=</span> <span class="s1">&#39;mysessions.custom_cached_db_backend&#39;</span>

    <span class="c1"># ...</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="s-session-ids-in-urls">
<span id="session-ids-in-urls"></span><h2>URL中的会话ID<a class="headerlink" href="#session-ids-in-urls" title="永久链接至标题">¶</a></h2>
<p>Django会话框架完全是基于cookie的。 正如PHP所做的那样，它不会回退到将会话ID放置在URL中作为最后的手段。 这是一个有意设计的决定。 这种行为不仅使URL变得很难看，而且使您的站点容易受到会话ID的盗用。</p>
</div>
</div>


          </div>
        </div>
      </div>
      
        
          <div class="yui-b" id="sidebar">
            
      <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../../contents.html">Table of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">如何使用会话</a><ul>
<li><a class="reference internal" href="#enabling-sessions">打开会话</a></li>
<li><a class="reference internal" href="#configuring-the-session-engine">配置会话(session)引擎</a><ul>
<li><a class="reference internal" href="#using-database-backed-sessions">使用数据库支持的会话</a></li>
<li><a class="reference internal" href="#using-cached-sessions">使用缓存会话</a></li>
<li><a class="reference internal" href="#using-file-based-sessions">使用基于文件的会话</a></li>
<li><a class="reference internal" href="#using-cookie-based-sessions">使用基于cookie的会话</a></li>
</ul>
</li>
<li><a class="reference internal" href="#using-sessions-in-views">在视图中使用会话</a><ul>
<li><a class="reference internal" href="#session-serialization">会话序列化</a><ul>
<li><a class="reference internal" href="#bundled-serializers">绑定序列化</a></li>
<li><a class="reference internal" href="#write-your-own-serializer">编写自定义的序列化器</a></li>
</ul>
</li>
<li><a class="reference internal" href="#session-object-guidelines">会话对象指南</a></li>
<li><a class="reference internal" href="#examples">示例</a></li>
</ul>
</li>
<li><a class="reference internal" href="#setting-test-cookies">测试 <code class="docutils literal notranslate"><span class="pre">cookies</span></code> 设置</a></li>
<li><a class="reference internal" href="#using-sessions-out-of-views">在视图外使用会话</a></li>
<li><a class="reference internal" href="#when-sessions-are-saved">当保存会话时</a></li>
<li><a class="reference internal" href="#browser-length-sessions-vs-persistent-sessions">Browser-length 会话 vs 持久会话</a></li>
<li><a class="reference internal" href="#clearing-the-session-store">清除会话存储</a></li>
<li><a class="reference internal" href="#settings">配置</a></li>
<li><a class="reference internal" href="#session-security">会话安全</a></li>
<li><a class="reference internal" href="#technical-details">技术细节</a><ul>
<li><a class="reference internal" href="#the-sessionstore-object"><code class="docutils literal notranslate"><span class="pre">SessionStore</span></code> 对象</a></li>
</ul>
</li>
<li><a class="reference internal" href="#extending-database-backed-session-engines">扩展数据库支持的会话引擎</a><ul>
<li><a class="reference internal" href="#example">例如</a></li>
</ul>
</li>
<li><a class="reference internal" href="#session-ids-in-urls">URL中的会话ID</a></li>
</ul>
</li>
</ul>

  <h4>上一个主题</h4>
  <p class="topless"><a href="middleware.html"
                        title="上一章">中间件</a></p>
  <h4>下一个主题</h4>
  <p class="topless"><a href="../forms/index.html"
                        title="下一章">使用表单</a></p>
  <div role="note" aria-label="source link">
    <h3>本页</h3>
    <ul class="this-page-menu">
      <li><a href="../../_sources/topics/http/sessions.txt"
            rel="nofollow">显示源代码</a></li>
    </ul>
   </div>
<div id="searchbox" style="display: none" role="search">
  <h3>快速搜索</h3>
    <div class="searchformwrapper">
    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" />
      <input type="submit" value="转向" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    </div>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
              <h3>Last update:</h3>
              <p class="topless">12月 07, 2021</p>
          </div>
        
      
    </div>

    <div id="ft">
      <div class="nav">
    &laquo; <a href="middleware.html" title="中间件">previous</a>
     |
    <a href="../index.html" title="使用 Django" accesskey="U">up</a>
   |
    <a href="../forms/index.html" title="使用表单">next</a> &raquo;</div>
    </div>
  </div>

      <div class="clearer"></div>
    </div>
  </body>
</html>